<template>
	<scroll-view 
		:style="{height: height+'px'}"
		:upper-threshold="80"
		:refresher-threshold="50"
		scroll-y
		enable-back-to-top
		scroll-with-animation
		refresher-enabled
		refresher-default-style="none"
		@refresherpulling="refresherpulling"
		@refresherrefresh="onRefresh"
		:refresher-triggered="triggered"
		@scrolltolower="onLoadMore"
	>
		<!-- 自定义下拉刷新 -->
		<view class="scroll_down_content">
			<image class="load_icon" :class="{'loading_rotate': triggered}" :style="{transform: 'rotate('+refreshIconAngle+'deg)'}" :src="require('./circle.png')" mode=""></image>
			<text>{{downText}}</text>
		</view>
		
		<!-- 骨架图 -->
		<view v-show="firstQuery" class="skeleton">
			<image class="_img" :src="require('./skeleton'+this.skeletonStyle+'.png')" mode="widthFix" lazy-load v-for="(item, index) in 20" :key="index" />
		</view>
		
		<!-- list 列表 -->
		<slot v-if="list.length>0"></slot>
		
		<!-- 暂无数据图 -->
		<view class="empty_box" :style="{height: height+'px'}" v-if="!firstQuery && list.length === 0">
			<image class="_icon" :src="require('./empty.png')" lazy-load mode="widthFix" />
			<view class="_text" v-html="emptyText"></view>
			<view class="_btn" v-if="addBtnText" hover-class="hover_class" @tap="addBtn">{{addBtnText}}</view>
		</view>
		
		<!-- 加载更多与没有更多数据 -->
		<view class="safe-area-inset-bottom" v-if="!firstQuery && list.length>0">
			<view class="noData" v-if="isNoMoreData" v-html="noMoreDataText"></view>
			<view class="pullUp" v-else>
				<image class="load_icon loading_rotate" :src="require('./loading.png')" mode=""></image>
				<view v-html="pullUpText"></view>
			</view>
		</view>
	</scroll-view>
</template>

<script>
	export default {
		name:"uni-list-view",
		props: {
			// scroll-view 的高度
			height: {
				type: Number,
				default: 1000,
			},
			// 请求list的地址
			url: {
				type: String,
				default: ""
			},
			// 请求参数
			params: {
				type: Object,
				default(){
					return {}
				},
			},
			// 没有更多数据
			noMoreDataText: {
				type: String,
				default: "—— 没有更多数据了 ——"
			},
			// 没有数据
			emptyText: {
				type: String,
				default: "暂无数据"
			},
			// 没有数据 去创建
			addBtnText:{
				type: String,
				default: ""
			},
			// 上拉加载更多
			pullUpText: {
				type: String,
				default: "上拉加载更多"
			},
			// 骨架 01 - 05
			skeletonStyle: {
				type: String,
				default: "01"
			},
			// 接口返回的 list 的key值
			listKey: {
				type: String,
				default: 'content'
			},
			// 请求 pageSize 的 key
			pageSizeKey: {
				type: String,
				default: 'pageSize'
			},
			// 请求 pageNum 的 key
			pageNumKey: {
				type: String,
				default: 'page'
			},
			// 请求方式
			requestMethod: {
				type: String,
				default: 'POST'
			},
			// 总条数
			totalNumKey: {
				type: String,
				default: 'totalElements',
			},
			// 分页的开始页
			defaultPageNum: {
				type: Number,
				default: 1
			},
			// 分页的开始数量
			defaultPageSize: {
				type: Number,
				default: 10
			},
			// 参数集结完毕
			paramsComplete: {
				type: Boolean,
				default: true
			}
		},
		data() {
			return {
				list: [], // list
				requestParams: {}, // 请求参数
				firstQuery: true, // 是否第一次请求 
				requesting: false, // 请求中
				isNoMoreData: false, // 没有更多的数据了
				triggered: false, //下拉刷新 状态（true 打开， false 关闭）
				downText: '下拉刷新',
				refreshIconAngle: 0
			};
		},
		created() {
			//请求数据
			if(this.paramsComplete){
				this.initData(false)
			}
		},
		watch: {
			params: {
				handler(){
					if(this.paramsComplete){
						this.initData(false)
					}
				},
				deep: true,
			}
		},
		methods:{
			// 加载数据
			async initData(loadMore=false){
				// 请求中
				if(this.requesting) return
				// 没有数据了
				if(loadMore && this.isNoMoreData) return
				
				this.requesting = true;
				
				// 初始化给 requestParams 赋值
				// if(Object.keys(this.requestParams).length===0){
					this.requestParams = {...this.params};
				// }
				
				// 判断 requestParams 中有没有 pageSize
				if(typeof(this.requestParams[this.pageSizeKey])==='undefined'){
					this.requestParams[this.pageSizeKey] = this.defaultPageSize
					
				}
				// 判断 requestParams 中有没有 pageNum
				if(typeof(this.requestParams[this.pageNumKey])==='undefined'){
					this.requestParams[this.pageNumKey] = this.defaultPageNum
				}
				
				if(loadMore){
					// 加载更多的时候 pageNum +1
					this.requestParams[this.pageNumKey]+=1
				}else{
					// 刷新的时候pageNum 赋初始值
					this.requestParams[this.pageNumKey] = this.defaultPageNum;
					
					this.isNoMoreData = false;
					// 刷新的时候 把骨架 漏出来，并清空数据
					this.firstQuery = true;
					this.list = [];
					this.$emit('loadData', [], 1, 0)
					await this.delay(300)
				}
				
				// 开始请求
				return new Promise(resolve=>{
					
					this.$request({
						url: this.url,
						data: this.requestParams,
						method: this.requestMethod,
						errorToast: false, // TODO 后面要删除
						success: (res)=>{
							let tempArr = res.data[this.listKey];
							let pageNum = 1;
							
							// 请求页数 * 请求数量 >= 总量  说明没有数据了
							if(this.requestParams[this.pageSizeKey] * this.requestParams[this.pageNumKey] >= res.data[this.totalNumKey]){
								this.isNoMoreData = true
								pageNum = this.requestParams[this.pageNumKey]
							}
							
							this.list = loadMore?this.list.concat(tempArr):tempArr;
							
							this.$emit('loadData', this.list, pageNum, res.data[this.totalNumKey])
							
							resolve(true)
						},
						fail: ()=>{
							resolve(false)
						},
						complete: ()=>{
							// 请求完成
							this.firstQuery = false;
							this.requesting = false;
							this.downText = '加载成功'
						}
					})
				})
				
			},
			
			// 监听下拉动画
			refresherpulling(e) {
				// 下拉距离
				let dy = e.detail.dy;
				this.refreshIconAngle = dy*2;
				if(dy<80){
					this.downText = '下拉刷新'
				}else if(dy>=80){
					this.downText = '释放更新'
				}
			},
			
			// 刷新
			async onRefresh() {
				this.triggered = true;
				this.downText = '加载中...'
				let date1 = new Date().getTime();
				await this.initData(false);
				let date2 = new Date().getTime();
				let dis = date2 - date1;
				
				// 保障能看到刷新的效果，最低停留1秒
				// console.log('dis', dis);
				await this.delay(dis>1000?300:1000);
				this.triggered = false;
			},
			
			// 加载更多
			async onLoadMore() {
				// 请求速度过快，延缓请求
				await this.delay(500)
				await this.initData(true);
			},
			
			// 新增按钮 或者 刷新重试按钮
			addBtn() {
				this.$emit('btnClick')
			},
			
			// 延迟
			delay(timer){
				return new Promise(resolve => {
					setTimeout(()=>{ resolve(true) }, timer)
				})
			}
		},
		beforeDestroy() {
			this.triggered = false;
		}
	}
</script>

<style lang="scss" scoped>
	.scroll_down_content{
		position: absolute;
		left: 0;
		right: 0;
		top: -32px;
		display: flex;
		justify-content: center;
		align-items: center;
		color: #ABABAB;
		font-size: 28rpx;
	}
	.skeleton {
	  ._img {
	    width: 100%;
	    animation: skeleton-loading 1.5s ease infinite;
	  }
	  @keyframes skeleton-loading {
	    0% {
	      opacity: 1;
	    }
	    50% {
	      opacity: 0.6;
	    }
	    100% {
	      opacity: 1;
	    }
	  }
	}
	
	.empty_box{
		display: flex;
		align-items: center;
		justify-content: center;
		flex-direction: column;
		._icon{
			width: 250rpx;
		}
		._text{
			font-size: 28rpx;
			color: #808080;
		}
		._btn{
			margin-top: 25rpx;
			width: 300rpx;
			height: 80rpx;
			text-align: center;
			line-height: 80rpx;
			background-color: #FFA115;
			color: #fff;
			font-size: 30rpx;
			border-radius: 10rpx;
		}
	}
	
	.hover_class{
		opacity: 0.8;
	}
	
	.noData, .pullUp{
		text-align: center;
		font-size: 28rpx;
		color: #555;
		padding: 30rpx;
	}
	.pullUp{
		display: flex;
		align-items: center;
		justify-content: center;
	}
	
	.safe-area-inset-bottom{
		padding-bottom: 0;
		padding-bottom: constant(safe-area-inset-bottom);
		padding-bottom: env(safe-area-inset-bottom);
	}
	.load_icon{
		width: 48rpx;
		height: 48rpx;
		margin-right: 15rpx;
	}
	.loading_rotate{
		animation: loadingRotate 1s linear infinite;
	}
	@keyframes loadingRotate {
	  0%{ transform: rotate(0)}
	  100% { transform: rotate(365deg)}
	}
</style>